#pragma once
#include "nds.h"
#include "../include/enum.h"
#include <vector>
#include "Tools.hpp"
#include <map>


static const int SPRITE_DMA_CHANNEL = 3;
class Hero;
class DecorElement;
class Enemy;
class ManaBottle;
class Hud;

typedef struct 
{
	int x;
	int y;
	u16* sprite_gfx_mem;
	u8*  frame_gfx;
	int state;
	int anim_frame;
}HeroSprite;

/*! \class SpritesManager
	This class handles the loading of sprites and initialize the OAM
	
*/ 

class SpritesManager
{
public:

	//! Local copy of the DS OAM to manipulate asynchronously
	OAMTable * oam;
	OAMTable * oamSub;
	//! Next memory location to store sprites data in memory
	unsigned int speedBase;
	int nextTileIdx;
	unsigned int nextSpriteId;
	int nextTileIdxSub;
	unsigned int nextSpriteIdSub;
	unsigned int nextPalId; 
	unsigned int nextPalIdSub; 
	Hero* hero;
	Hud* hud;
	std::vector<Enemy*> enemies;
	std::vector<ManaBottle*> manaBottles;
	std::vector<DecorElement*> decorElements;

	unsigned int groundFirstId;

	Sprite* endSprite;
	int positionEndSprite;

	//Id to keep the location of the data in the NDS memory
	unsigned int GROUND;
	unsigned int GROUND_PAL;
	unsigned int MANA;
	unsigned int MANA_PAL;
	unsigned int MANA_TOP;
	unsigned int MANA_PAL_TOP;
	unsigned int BARREL;
	unsigned int BARREL_PAL;
	//unsigned int BARREL_TOP;
	//unsigned int BARREL_PAL_TOP;
	unsigned int ROCK;
	unsigned int ROCK_PAL;
	//unsigned int ROCK_TOP;
	//unsigned int ROCK_PAL_TOP;
	unsigned int END_SPRITE;

	unsigned int PLATEFORM_BEG;
	unsigned int PLATEFORM_MID;
	unsigned int PLATEFORM_END;
	unsigned int PLATEFORM_PAL;

	unsigned int PLATEFORM_BEG_TOP;
	unsigned int PLATEFORM_MID_TOP;
	unsigned int PLATEFORM_END_TOP;
	unsigned int PLATEFORM_PAL_TOP;

	unsigned int HUMAN_1;
	unsigned int HUMAN_2;
	unsigned int HUMAN_3;
	unsigned int HUMAN_PAL;

	unsigned int HUMAN_1_TOP;
	unsigned int HUMAN_2_TOP;
	unsigned int HUMAN_3_TOP;
	unsigned int HUMAN_PAL_TOP;

	unsigned int ZOMBIE_1;
	unsigned int ZOMBIE_2;
	unsigned int ZOMBIE_3;
	unsigned int ZOMBIE_PAL;
		
	unsigned int ZOMBIE_1_TOP;
	unsigned int ZOMBIE_2_TOP;
	unsigned int ZOMBIE_3_TOP;
	unsigned int ZOMBIE_PAL_TOP;

	unsigned int VAMPIRE_1;
	unsigned int VAMPIRE_2;
	unsigned int VAMPIRE_3;
	unsigned int VAMPIRE_PAL;

	unsigned int VAMPIRE_1_TOP;
	unsigned int VAMPIRE_2_TOP;
	unsigned int VAMPIRE_3_TOP;
	unsigned int VAMPIRE_PAL_TOP;

	unsigned int BAT_1;
	unsigned int BAT_2;
	unsigned int BAT_3;
	unsigned int BAT_PAL;

	unsigned int BAT_1_TOP;
	unsigned int BAT_2_TOP;
	unsigned int BAT_3_TOP;
	unsigned int BAT_PAL_TOP;
	
	unsigned int FATZOMBIE_1;
	unsigned int FATZOMBIE_2;
	unsigned int FATZOMBIE_3;
	unsigned int FATZOMBIE_PAL;

	unsigned int FATZOMBIE_1_TOP;
	unsigned int FATZOMBIE_2_TOP;
	unsigned int FATZOMBIE_3_TOP;
	unsigned int FATZOMBIE_PAL_TOP;

	unsigned int WEREWOLF_1;
	unsigned int WEREWOLF_2;
	unsigned int WEREWOLF_3;
	unsigned int WEREWOLF_PAL;

	unsigned int WEREWOLF_1_TOP;
	unsigned int WEREWOLF_2_TOP;
	unsigned int WEREWOLF_3_TOP;
	unsigned int WEREWOLF_PAL_TOP;
	
	unsigned int HUNTER_1;
	unsigned int HUNTER_2;
	unsigned int HUNTER_3;
	unsigned int HUNTER_PAL;

	unsigned int HUNTER_1_TOP;
	unsigned int HUNTER_2_TOP;
	unsigned int HUNTER_3_TOP;
	unsigned int HUNTER_PAL_TOP;
	
	unsigned int ENEMY_1;
	unsigned int ENEMY_2;
	unsigned int ENEMY_3;
	unsigned int ENEMY_PAL;

	unsigned int ENEMY_1_TOP;
	unsigned int ENEMY_2_TOP;
	unsigned int ENEMY_3_TOP;
	unsigned int ENEMY_PAL_TOP;

	unsigned int PROGRESS_BAR_BLOC;
	unsigned int PROGRESS_BAR_BLOC_PAL;
	unsigned int PROGRESS_BAR_END;
	unsigned int PROGRESS_BAR_END_PAL;
	unsigned int PROGRESS_MARKER_RITH;
	unsigned int PROGRESS_MARKER_RITH_PAL;
	unsigned int PROGRESS_MARKER_ENEMY;
	unsigned int PROGRESS_MARKER_ENEMY_PAL;

	unsigned int MANA_BAR_BEG;
	unsigned int MANA_BAR_BLOC;
	unsigned int MANA_BAR_END;	
	unsigned int MANA_BAR_EMPTY;
	unsigned int MANA_BAR_PAL;

	unsigned int HEALTH_BAR_BEG;
	unsigned int HEALTH_BAR_BLOC;
	unsigned int HEALTH_BAR_END;
	unsigned int HEALTH_BAR_EMPTY;
	unsigned int HEALTH_BAR_PAL;

	unsigned int SHAPESHIFT_ICON_BLOC;
	unsigned int SHAPESHIFT_ICON_UP;
	unsigned int SHAPESHIFT_ICON_DOWN;
	unsigned int SHAPESHIFT_ICON_PAL;

	///END ID

	std::map <unsigned int, bool> enemiesOAMID;
	std::map <unsigned int, bool> decorElementsOAMID;
	std::map <unsigned int, bool> manaBottlesOAMID;
	std::map <unsigned int, bool> decorElementsTopOAMID;
	std::map <unsigned int, bool> manaBottlesTopOAMID;
	
	Collision collisionState;	

	static const int BYTES_PER_16_COLOR_TILE = 32;
    static const int COLORS_PER_PALETTE = 16;
    static const int BOUNDARY_VALUE = 32; // This is the default boundary value                                       
    static const int OFFSET_MULTIPLIER = BOUNDARY_VALUE / sizeof(SPRITE_GFX[0]);

	//! The scrolling speed
	unsigned int spriteSpeed;
	bool spriteScroll;
	
	//elapsed time ticks since the last scroll for the sprites
	unsigned int spritesTicks; 

	SpritesManager(void);
	~SpritesManager(void);

	/*! \fn updateOAM
		\brief copy the OAM
		Performs a copy of our local OAM to the DS OAM. Must be called at each frame.
	*/
	void updateOAM();

	void initOAM();

	/*! \fn buildHero
		\brief load the sprite into memory 
		load the hero into memory and OAM and display it
		load the other sprites into memory and set the ID the use them
		
	*/

	void buildSprites(const std::vector<DecorFile> & decorInfo, const std::vector<EnemyFile> & enemiesInfo, const std::vector<ManaFile> & manaInfo, int levelSize, std::vector<int> _forbiddenTransfos);


	/*! \fn loadSpriteIntoRam
		\brief load sprite gfx into the nds RAM without loading it in the OAM
		This function loads tiles and palette at the same time. For separeted loading, see loadTilesIntoRam and loadPalIntoRam
		

	*/
	void loadSpriteIntoRam(Screen pos, const unsigned int * tiles, int tilesLen, const unsigned short* pal, int palLen, unsigned int * tileId, unsigned int * palId);

	/*! \fn loadTilesIntoRam
		\brief load only the tiles data into the RAM and fill an ID refering to it

		\param pos : BOTTOM or TOP : the screen on with the sprite will be displayed
		\param tiles : tiles datas provided by the grit .h  file
		\param tilesLen : tiles datas length provided by the grit .h  file
		\param tileId : ID declared in SpriteManager to store the index of the tiles in memory.

	*/
	void loadTilesIntoRam(Screen pos, const unsigned int * tiles, int tilesLen, unsigned int * tileId);

	/*! \fn loadPaletteIntoRam
		\brief load only the palette data into the RAM and fill an ID refering to it

		\param pos : BOTTOM or TOP : the screen on with the sprite will be displayed
		\param pal : palette datas provided by the grit .h  file
		\param pal : palette datas length MUST BE SET TO 32. Value provided by GRIT is WRONG !!
		\param tileId : ID declared in SpriteManager to store the index of the palette in memory.
	*/
	void loadPalIntoRam(Screen pos, const unsigned short* pal, int palLen, unsigned int * palId);

	void scrollSprites();

	void updateHud(int scrollValue, int pursuerScrollValue, int levelSize);


};

